package dataAnalyze.iteration1;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Vector;

public class BaseLine1 {
	
	public Map<Integer, Double> bm = null;
	public Map<Integer, Double> bu = null;
	public double r_estimate = 0;
	
	private double var1 = 25;
	private double var2 = 10;
	
	public BaseLine1()
	{
		bm = new HashMap<Integer, Double>();
		bu = new HashMap<Integer, Double>();
	}
	
	public void calc_R_estimate(Map<Integer, Movie> movies)
	{
		int num = 0;
		double sum = 0;
		Iterator<Entry<Integer, Movie>> it = movies.entrySet().iterator();
		while(it.hasNext())
		{
			Map.Entry<Integer, Movie> entry = (Map.Entry<Integer, Movie>)it.next();
			Movie m = entry.getValue();
			Iterator<Entry<Integer, Rating>> iter = m.rates.entrySet().iterator();
			while(iter.hasNext())
			{
				Map.Entry<Integer, Rating> entryy = (Map.Entry<Integer, Rating>)iter.next();
				sum+= entryy.getValue().getScore();
				num++;
			}
		}
		this.r_estimate = sum/(double)num;
	}
	
	public void calc_Bm(Map<Integer, Movie> movies)
	{
		bm.clear();
		Iterator<Entry<Integer, Movie>> it = movies.entrySet().iterator();
		while(it.hasNext())
		{
			Map.Entry<Integer, Movie> entry = (Map.Entry<Integer, Movie>)it.next();
			Movie m = entry.getValue();
			double tempSum = 0;
			Iterator<Entry<Integer, Rating>> iter = m.rates.entrySet().iterator();
			while(iter.hasNext())
			{
				Map.Entry<Integer, Rating> entryy = (Map.Entry<Integer, Rating>)iter.next();
				tempSum += entryy.getValue().getScore() - this.r_estimate;
			}
			tempSum = tempSum/(var1 + m.rates.size());
			bm.put(entry.getKey(), tempSum);
		}
	}
	
	public void calc_Bu(Map<Integer, Movie> movies, Map<Integer, Vector<Integer>> user_rating_records)
	{
		bu.clear();
		
		Iterator<Entry<Integer, Vector<Integer>>> iter = user_rating_records.entrySet().iterator();
		while(iter.hasNext())
		{
			Map.Entry<Integer, Vector<Integer>> entry = (Map.Entry<Integer, Vector<Integer>>)iter.next();
			Vector<Integer> tempVector = entry.getValue();
			int user_id = entry.getKey();
			
			double tempSum = 0;
			for (int i = 0; i < tempVector.size(); i++)
			{
				int movie_id = tempVector.elementAt(i);
				Movie m = movies.get(movie_id);
				Rating r = m.rates.get(user_id);
				tempSum += r.getScore() - this.r_estimate - bm.get(movie_id);
			}
			
			bu.put(user_id, tempSum/(tempVector.size()+var2));
		}
		
		
	}

	public void getResult(Map<Integer, Movie> movies, Map<Integer, Vector<Integer>> user_rating_records, Map<Integer, Vector<Integer>> testSet)
	{
		calc_R_estimate(movies);
		System.out.println("step1 Finished!!!");
		calc_Bm(movies);
		System.out.println("step2 Finished!!!");
		calc_Bu(movies, user_rating_records);
		System.out.println("step3 Finished!!!");
		
		double sumError = 0;
		double totalCase = 0;
		Iterator<Entry<Integer, Vector<Integer>>> iter = testSet.entrySet().iterator();
		while(iter.hasNext())
		{
			Map.Entry<Integer, Vector<Integer>> entry = (Map.Entry<Integer, Vector<Integer>>)iter.next();
			int movie_id = entry.getKey();
			Vector<Integer> user_ids = entry.getValue();
			Map<Integer, Rating> rates = movies.get(movie_id).rates;
			
			for (int i = 0; i < user_ids.size(); i++)
			{
				int user_id = user_ids.elementAt(i);
				double predictScore = this.r_estimate;
				
				if (bu.containsKey(user_id))
					predictScore += bu.get(user_id);
				
				if (bm.containsKey(movie_id))
					predictScore += bm.get(movie_id);
				BigDecimal bd = new BigDecimal(predictScore).setScale(0, BigDecimal.ROUND_HALF_UP);
				double tempError = Math.pow(rates.get(user_id).getScore()-bd.intValue(),2);
				sumError += tempError;
				totalCase += 1;
			}
			
		}
		
		System.out.println(Math.sqrt(sumError/totalCase));
		System.out.println(totalCase);
	}
}
